﻿namespace Blaze.Framework
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using UnityEngine;

    /// <summary>
    /// 统一管理所有的<see cref="IAppConfig"/>的加载和缓存。
    /// </summary>
    public static class AppConfigManager
    {
        /// <summary>
        /// 加载指定类型的应用配置。
        /// 先从StreamingAssets下加载，然后用PersistentData下的配置覆盖。
        /// </summary>
        public static T Get<T>() where T : IAppConfig, new()
        {
            return (T) Get(typeof(T));
        }

        /// <summary>
        /// 加载指定类型的应用配置。
        /// 先从StreamingAssets下加载，然后用PersistentData下的配置覆盖。
        /// </summary>
        public static IAppConfig Get(Type type)
        {
            IAppConfig appConfig;
            if (mCache.TryGetValue(type, out appConfig))
                return appConfig;

            var ret = LoadFromStreamingAssets(type);
            if (ret == null)
                ret = (IAppConfig) Activator.CreateInstance(type);
            var name = getConfigName(type);
            var path = PathUtility.GetPersistentDataPath(name);
            if (File.Exists(path))
            {
                var json = File.ReadAllText(path);
                JsonUtility.FromJsonOverwrite(json, ret);
            }
            mCache[type] = ret;
            return ret;
        }

        /// <summary>
        /// 尝试从PersistentData目录中加载配置，若配置不存在则返回空。
        /// </summary>
        /// <returns>加载成功的配置</returns>
        public static T LoadFromPersistent<T>() where T : IAppConfig, new()
        {
            var name = getConfigName(typeof(T));
            var path = PathUtility.GetPersistentDataPath(name);
            if (!File.Exists(path))
                return default(T);

            var ret = new T();
            var json = File.ReadAllText(path);
            JsonUtility.FromJsonOverwrite(json, ret);
            return ret;
        }

        /// <summary>
        /// 尝试从PersistentData目录中加载配置，若配置不存在则返回空。
        /// </summary>
        /// <returns>加载成功的配置</returns>
        public static IAppConfig LoadFromPersistent(Type configType)
        {
            var name = getConfigName(configType);
            var path = PathUtility.GetPersistentDataPath(name);
            if (!File.Exists(path))
                return null;

            var ret = Activator.CreateInstance(configType);
            var json = File.ReadAllText(path);
            JsonUtility.FromJsonOverwrite(json, ret);
            return (IAppConfig) ret;
        }

        /// <summary>
        /// 尝试从StreamingAssets目录中加载配置，若配置不存在则返回空。
        /// </summary>
        public static T LoadFromStreamingAssets<T>() where T : IAppConfig, new()
        {
            var path = getConfigName(typeof(T));
            if (!StreamingAssets.Exists(path))
                return default(T);

            var ret = new T();
            var bytes = StreamingAssets.Load(path);
            var json = Encoding.UTF8.GetString(bytes);
            JsonUtility.FromJsonOverwrite(json, ret);
            return ret;
        }

        /// <summary>
        /// 尝试从StreamingAssets目录中加载配置，若配置不存在则返回空。
        /// </summary>
        public static IAppConfig LoadFromStreamingAssets(Type configType)
        {
            var path = getConfigName(configType);
            if (!StreamingAssets.Exists(path))
                return null;

            var ret = Activator.CreateInstance(configType);
            var bytes = StreamingAssets.Load(path);
            var json = Encoding.UTF8.GetString(bytes);
            JsonUtility.FromJsonOverwrite(json, ret);
            return (IAppConfig) ret;
        }

        /// <summary>
        /// 重置所有缓存的配置。
        /// </summary>
        public static void Reset()
        {
            mCache.Clear();
        }

        private static string getConfigName(Type configType)
        {
            var fieldInfo = configType.GetField("FileName", BindingFlags.Public | BindingFlags.Static);
            return (string) fieldInfo.GetValue(null);
        }

        private static readonly Dictionary<Type, IAppConfig> mCache = new Dictionary<Type, IAppConfig>();
    }
}